package com.jason.photography.api.utl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.StrPool;
import com.jason.common.core.exception.BizException;
import com.luciad.imageio.webp.WebPReadParam;
import com.luciad.imageio.webp.WebPWriteParam;
import jakarta.annotation.PostConstruct;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.List;

/**
 * Webp图片工具类
 * <p>
 * Webp是一种由Google开发的现代图像格式，旨在提供更高的压缩率和更好的图像质量，相比于传统的JPEG、PNG等格式，能够显著减少图像文件的大小。Webp图像通常具有更小的文件大小，因此可以加快网页加载速度，节省带宽和用户的流量消耗。
 * Webp图像支持有损压缩和无损压缩两种模式。在有损压缩模式下，WebP图像通常能够实现较高的压缩比，而在无损压缩模式下，Webp图像则可以保留原始图像的质量而实现较小的文件体积。
 * Webp格式的优势主要包括：
 * 更高的压缩率： Webp图像通常比JPEG图像具有更小的文件大小，同时保持相近甚至更好的图像质量。
 * 更快的加载速度： 由于文件大小更小，Webp图像能够更快地加载，从而改善网页加载性能，提升用户体验。
 * 广泛的兼容性： Webp图像在现代浏览器中得到了广泛支持，包括Chrome、Firefox、Edge等浏览器，同时也可以通过Polyfill等方式在不支持WebP的浏览器上进行兼容性处理。
 * Webp格式已经成为常用的图像格式之一，特别是对于需要大量图片展示的网站，如电子商务平台、社交媒体和新闻网站等。
 *
 * @author gzc
 * @since 2024/3/6 4:24
 **/
@Slf4j
public class WebpImgUtil {
    public static void main(String[] args) throws Exception {
//        addTextWatermark("E:\\video-test\\a.webp", "E:\\video-test\\a_1.webp", "阿来得及啊上课拉家带口拉萨较大立卡");
//        addTextWatermark("E:\\video-test\\a.webp", "E:\\video-test\\a_2.jpg", "阿来得及啊上课拉家带口拉萨较大立卡");
//        addTextWatermark("E:\\video-test\\40.png", "E:\\video-test\\40_1.webp", "阿来得及啊上课拉家带口拉萨较大立卡");
//        double v = calculateCompressRatio("E:\\video-test\\c.jpg", "E:\\video-test\\c_1.webp");
//        System.out.println(v);
        webpToOtherFormat("E:\\video-test\\a.webp","E:\\video-test\\aaaaaaaaa.png","png");
        otherFormatToWebp("E:\\video-test\\aaaaaaaaa.png","E:\\video-test\\bbbbbbbbbbbb.webp");
    }

    public static void otherFormatToWebp(String inputFilePath, String outputFilePath) throws IOException {
        // 获取图片格式
        String name = FileUtil.getName(outputFilePath);
        int endIndex = name.lastIndexOf(".");
        String substring = name.substring(0, endIndex);
        String newOutputFilePath = FileUtil.getParent(outputFilePath, 1)
                + File.separator +
                substring + ".webp";
        // 读取文件
        BufferedImage image = ImageIO.read(FileUtil.file(inputFilePath));
        ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next();
        WebPWriteParam writeParam = new WebPWriteParam(writer.getLocale());
        writeParam.setCompressionMode(WebPWriteParam.MODE_EXPLICIT);
        writer.setOutput(new FileImageOutputStream(FileUtil.touch(newOutputFilePath)));
        // 编码
        writer.write(null, new IIOImage(image, null, null), writeParam);
    }

    public static void webpToOtherFormat(String inputFilePath, String outputFilePath, String formatName) throws IOException {
        ImageReader reader = ImageIO.getImageReadersByMIMEType("image/webp").next();
        WebPReadParam readParam = new WebPReadParam();
        readParam.setBypassFiltering(true);
        reader.setInput(new FileImageInputStream(FileUtil.touch(inputFilePath)));
        // 解码
        BufferedImage image = reader.read(0, readParam);
        ImageIO.write(image, formatName, FileUtil.touch(outputFilePath));
    }

    public static void addTextWatermarkAndConvertWebp(String inputFilePath, String outputFilePath, String watermarkText) throws IOException {
        // 读取原始图片
        File inputFile = FileUtil.file(inputFilePath);
        BufferedImage inputImage = ImageIO.read(inputFile);
//        BufferedImage watermarkedImage = createWatermarkedImage(inputImage, true);
    }

    public static void addTextWatermark(String inputFilePath, String outputFilePath, String watermarkText) throws IOException, InterruptedException {
        // 获取转换类型
        int convertType = getConvertType(inputFilePath, outputFilePath);

        // 读取原始图片
        BufferedImage inputImage = ImageIO.read(FileUtil.file(inputFilePath));
        // 创建图层
        BufferedImage watermarkedImage = createWatermarkedImage(inputImage, false);
        Graphics2D graphics = (Graphics2D) watermarkedImage.getGraphics();
        // 添加文字水印
        doAddTextWatermark(watermarkText, inputImage, graphics);
        if (convertType == -1) {
            throw new BizException("转换类型不匹配");
        }
        if (convertType == 0) {
            ImageIO.write(watermarkedImage, getTypeByPath(outputFilePath), FileUtil.touch(outputFilePath));
        }
        // 解压
        if (convertType == 1) {
            String path = outputFilePath.substring(0, outputFilePath.lastIndexOf(".")) + ".webp";
            ImageIO.write(watermarkedImage, "webp", new File(path));
            // 执行解压
            RandomAccessFile rw = new RandomAccessFile(new File(path), "r");

            ImageReader reader = ImageIO.getImageReadersByMIMEType("image/webp").next();
            WebPReadParam readParam = new WebPReadParam();
            readParam.setBypassFiltering(true);
            reader.setInput(new FileImageInputStream(rw));
            ImageIO.write(reader.read(0, readParam), getTypeByPath(outputFilePath), FileUtil.touch(outputFilePath));
            reader.abort();
            rw.close();
            FileUtil.del(path);
        }
        // 压缩
        if (convertType == 2) {
            IIOImage iioImage = new IIOImage(watermarkedImage, null, null);
            ImageWriter imageWriter = ImageIO.getImageWritersByMIMEType("image/webp").next();
            WebPWriteParam writeParam = new WebPWriteParam(imageWriter.getLocale());
            writeParam.setCompressionMode(WebPWriteParam.MODE_EXPLICIT);
//            writeParam.setCompressionQuality(0.7f);
            imageWriter.setOutput(new FileImageOutputStream(new File(outputFilePath)));
            imageWriter.write(null, iioImage, writeParam);
            imageWriter.abort();
        }
        // 释放资源
        graphics.dispose();
    }

    private static String getTypeByPath(String filePath) {
        int indexOf = filePath.lastIndexOf(StrPool.DOT);
        String substring = filePath.substring(indexOf + 1);
        List<String> list = Arrays.asList("png", "jpg", "jpeg", "webp", "bmp", "jpe");
        for (String imgType : list) {
            if (imgType.equalsIgnoreCase(substring)) {
                return imgType;
            }
        }
        return "";
    }

    private static int getConvertType(String inputFilePath, String outputFilePath) {
        int convertType = -1;
        String inputFileTypeName = getTypeByPath(inputFilePath);
        String outputFileTypeName = getTypeByPath(outputFilePath);
        // 不压缩，不解压
        if ("webp".equalsIgnoreCase(inputFileTypeName) && "webp".equalsIgnoreCase(outputFileTypeName)) {
            convertType = 0;
        }
        if (!"webp".equalsIgnoreCase(inputFileTypeName) && !"webp".equalsIgnoreCase(outputFileTypeName)) {
            convertType = 0;
        }
        // 解压
        if ("webp".equalsIgnoreCase(inputFileTypeName) && !"webp".equalsIgnoreCase(outputFileTypeName)) {
            convertType = 1;
        }
        // 压缩
        if (!"webp".equalsIgnoreCase(inputFileTypeName) && "webp".equalsIgnoreCase(outputFileTypeName)) {
            convertType = 2;
        }
        return convertType;
    }

    private static BufferedImage createWatermarkedImage(BufferedImage inputImage, boolean isWebp) throws IOException {
        // 创建一个带有水印的新图片
        BufferedImage watermarkedImage = new BufferedImage(inputImage.getWidth(), inputImage.getHeight(), BufferedImage.TYPE_INT_RGB);
        // 创建图样
        Graphics2D graphics = watermarkedImage.createGraphics();
        if (isWebp) {
            // 解码
            ImageReader reader = ImageIO.getImageReadersByMIMEType("image/webp").next();
            WebPReadParam readParam = new WebPReadParam();
            readParam.setBypassFiltering(true);
            reader.setInput(inputImage);
            graphics.drawImage(reader.read(0, readParam), 0, 0, null);
        } else {
            graphics.drawImage(inputImage, 0, 0, null);
        }
        return watermarkedImage;
    }

    private static void doAddTextWatermark(String watermarkText, BufferedImage inputImage, Graphics2D graphics) {
        int fontSize = calculateFontSize(inputImage);
        // 设置水印文本样式
        Font font = new Font("楷体", Font.PLAIN, fontSize);
        // 设置水印文本颜色和透明度
        Color color = new Color(255, 255, 255, 192);
        // 添加水印
        graphics.setColor(color);
        graphics.setFont(font);
        graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        // 计算文本水印位置
        Position position = calculateTextWatermarkPosition(inputImage);
        graphics.drawString(watermarkText, position.getX(), position.getY());
    }

    private static Position calculateTextWatermarkPosition(BufferedImage inputImage) {
        Position position = new Position();
        if (inputImage.getHeight() > inputImage.getWidth()) {
            position.setX(30);
            position.setY(40);
        } else {
            position.setX(15);
            position.setY(25);
        }
        return position;
    }

    @Data
    public static class Position {
        private int x;
        private int y;
    }


    /**
     * 计算水印文字大小
     *
     * @param image 图片
     * @return 文字字号
     */
    private static int calculateFontSize(BufferedImage image) {
        return image.getHeight() > image.getWidth() ? 32 : 18;
    }

    /**
     * 计算图片压缩率
     *
     * @param originalFilePath   原图路径
     * @param compressedFilePath 压缩后的图片路径
     * @return 压缩率
     */
    public static double calculateCompressRatio(String originalFilePath, String compressedFilePath) {
        File originalFile = new File(originalFilePath);
        File compressedFile = new File(compressedFilePath);
        // 获取图片文件大小
        long originalFileSize = originalFile.length();
        long compressedFileSize = compressedFile.length();
        return ((double) originalFileSize - compressedFileSize) / originalFileSize * 100;
    }

}
